package org.jmh.gift.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.jmh.gift.client.GiftClient;
import org.jmh.gift.constants.OrderConstants;
import org.jmh.gift.domain.GoodsSku;
import org.jmh.gift.domain.OrderGift;
import org.jmh.gift.domain.OrderGiftAddress;
import org.jmh.gift.domain.OrderGiftItem;
import org.jmh.gift.dto.PlaceOrderDTO;
import org.jmh.gift.enums.SystemErrorCode;
import org.jmh.gift.exception.BusinessException;
import org.jmh.gift.mapper.OrderGiftMapper;
import org.jmh.gift.service.IOrderGiftAddressService;
import org.jmh.gift.service.IOrderGiftItemService;
import org.jmh.gift.service.IOrderGiftService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.jmh.gift.strategy.IPlaceOrderSplitOrderStrategy;
import org.jmh.gift.strategy.PlaceOrderSplitOrderStrategyFactory;
import org.jmh.gift.util.AjaxResult;
import org.jmh.gift.util.CodeGenerateUtils;
import org.jmh.gift.util.JMHAssert;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lingfeng
 * @since 2024-08-06
 */
@Service
public class OrderGiftServiceImpl extends ServiceImpl<OrderGiftMapper, OrderGift> implements IOrderGiftService {
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private GiftClient giftClient;
    @Value("${jmh.splitOrder.strategy}")
    private String splitOrderStrategy;

    @Autowired
    private IOrderGiftItemService orderGiftItemService;

    @Autowired
    private IOrderGiftAddressService orderGiftAddressService;

    @Override
    public void placeOrder(PlaceOrderDTO dto) {
        //做判断，加锁
        JMHAssert.isNotBlank(dto.getParentOrderNo(), SystemErrorCode.RESPONSE_CODE_500);
        RLock lock = redissonClient.getLock(dto.getParentOrderNo());
        try {
            lock.lock();
            //根据parentOrderNo查询数据库,如果存在说明重复下单,返回错误信息
            int count = super.selectCount(new EntityWrapper<OrderGift>().eq("parent_order_no", dto.getParentOrderNo()));
            if (count > 0) {
                throw new BusinessException("请勿重复下单!");
            }
            String uniPayOrderSn = CodeGenerateUtils.generateUnionPaySn();
            dto.setUniPayOrderSn(uniPayOrderSn);
            Message<PlaceOrderDTO> message = MessageBuilder.withPayload(dto).build();
            TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
                    OrderConstants.PLACE_ORDER_TX_PRODUCER_GROUP,
                    OrderConstants.PLACE_ORDER_TX_TOPIC + ":" + OrderConstants.PLACE_ORDER_TX_TAG,
                    message, null
            );
            if (sendResult.getSendStatus() != SendStatus.SEND_OK ||
                    sendResult.getLocalTransactionState() != LocalTransactionState.COMMIT_MESSAGE) {
                throw new BusinessException("下单失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }
    }
    @Override
    public void ExecuteLocalTransaction(PlaceOrderDTO dto) {
        //远程调用礼物服务
        Map<Long, Integer> skuInfos = dto.getSkuInfos();
        Set<Long> skuIds = skuInfos.keySet();
        AjaxResult ajaxResult = giftClient.getSkuByIds(skuIds);
        System.out.println(ajaxResult.toString());
        if(!ajaxResult.getSuccess()){
            throw new RuntimeException("本地事务失败!");
        }
        String s = JSONObject.toJSONString(ajaxResult.getData());
        List<GoodsSku> goodsSkus = JSONArray.parseArray(s, GoodsSku.class);
        //根据获取到的商品信息（策略模式）
        IPlaceOrderSplitOrderStrategy strategy = PlaceOrderSplitOrderStrategyFactory.getStrategy(splitOrderStrategy);
        //按照店铺做拆单
        Map<Long, List<GoodsSku>> listMap = strategy.splitOrder(goodsSkus);
        //循环按照店铺分组后的结果
        for (Map.Entry<Long, List<GoodsSku>> next : listMap.entrySet()) {
            // 这个店铺中用户选择要购买的所有的商品
            List<GoodsSku> skus = next.getValue();
            //要按照拆单结果创建订单
            OrderGift orderGift = new OrderGift();
            orderGift.setId(IdUtil.getSnowflakeNextId());
            orderGift.setCreateTime(new Date());
            orderGift.setParentOrderNo(dto.getParentOrderNo());
            orderGift.setOrderNo(CodeGenerateUtils.generateOrderSn(dto.getUserId()));
            //支付总价格: 当前这个店铺下所购买的所有商品*数量的价格总和
            BigDecimal totalAmount = BigDecimal.ZERO;
            Integer totalCount = 0;
            orderGift.setStatus(0);
            orderGift.setUsername(dto.getUsername());
            orderGift.setUserId(dto.getUserId());
            orderGift.setRemark(dto.getRemark());
            orderGift.setPayType(dto.getPayType());
            //最后支付时间
            orderGift.setLastPayTime(DateUtil.offsetMinute(new Date(), 30));
            //创建订单
            List<OrderGiftItem> items = new ArrayList<>();
            for (GoodsSku goodsSku : skus) {
                //支付金额
                Integer num = skuInfos.get(goodsSku.getId());
                BigDecimal price = goodsSku.getPrice().multiply(new BigDecimal(num));
                totalAmount = totalAmount.add(price);
                totalCount += num;
                OrderGiftItem item = new OrderGiftItem();
                item.setOrderId(orderGift.getId());
                item.setOrderNo(orderGift.getOrderNo());
                item.setAmount(goodsSku.getPrice());
                item.setCount(num);
                item.setCreateTime(new Date());
                item.setSkuInfo(goodsSku.getSkuName());
                item.setSkuId(goodsSku.getId());
                item.setSpuId(goodsSku.getSpuId());
                item.setSpuName(goodsSku.getSpuName());
                items.add(item);
            }
            orderGift.setTotalAmount(totalAmount);
            orderGift.setTotalCount(totalCount);
            //保存订单
            super.insert(orderGift);
            //保存订单明细
            orderGiftItemService.insertBatch(items);
            //创建订单地址
            OrderGiftAddress address = dto.getAddress();
            address.setCreateTime(new Date().getTime());
            address.setUserId(dto.getUserId());
            address.setOrderId(orderGift.getId());
            address.setOrderSn(orderGift.getOrderNo());
            orderGiftAddressService.insert(address);
        }
        //发送rocketmq延迟消息
        Message<PlaceOrderDTO> message = MessageBuilder.withPayload(dto).build();
        SendResult sendResult = rocketMQTemplate.syncSend(
                OrderConstants.ORDER_TIMEOUT_NOPAY_TOPIC + ":" + OrderConstants.ORDER_TIMEOUT_NOPAY_TAG,
                message, 4000, 4
        );
        //回滚
        if(sendResult.getSendStatus() != SendStatus.SEND_OK){
            throw new RuntimeException("延迟失败!");
        }
    }

    @Override
    public Boolean CheckLocalTransaction(PlaceOrderDTO dto) {
        return null;
    }
}
